function Vue(options) {
  this.$data = this._data = options.data
  observer(this.$data)
  Object.keys(this.$data).forEach((key) => {
    this.proxy(key)
  })
  Compile(options.el, this)
}

//数据代理
Vue.prototype = {
  proxy: function (key) {
    Object.defineProperty(this, key, {
      get() {
        return this.$data[key]
      },
      set(val) {
        this.$data[key] = val
      },
    })
  },
}

//数据劫持
function observer(obj) {
  if (!obj || typeof obj !== 'object') return
  Object.keys(obj).forEach((key) => {
    var originValue = obj[key]
    observer(originValue)
    Object.defineProperty(obj, key, {
      get() {
        return originValue
      },
      set(val) {
        originValue = val
        observer(originValue)
      },
    })
  })
}

//模板编译
function Compile(el, vm) {
  if (typeof el === 'string') {
    vm.$el = document.querySelector(el)
  } else {
    vm.$el = el
  }

  //创建文档碎片
  var fragment = document.createDocumentFragment(),
    childNode
  while ((childNode = vm.$el.firstChild)) {
    fragment.appendChild(childNode)
  }

  //在文档碎片中替换模板
  replace(fragment)

  //最后将文档碎片中的内容一次性挂在真正的DOM树上
  vm.$el.appendChild(fragment)

  function replace(node) {
    if (node.nodeType === 3) {
      var txtContent = node.textContent
      var regMustache = /\{\{\s*(\S+)\s*\}\}/
      var regResult = regMustache.exec(txtContent)
      if (regResult) {
        var sourceValue = regResult[1]
          .split('.')
          .reduce((newObj, key) => newObj[key], vm)
        node.textContent = node.textContent.replace(regResult[0], sourceValue)
      }
      return
    }
    node.childNodes.forEach((child) => replace(child))
  }
}
